package com.dys.filter;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.dys.entity.CheckCode;
import com.dys.exception.KaptchaNotMatchException;
import com.google.code.kaptcha.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

/**
 * @Author: 疾风
 * @ClassName: KaptchaFilter
 * @Description: 自定义图形验证码校验过滤器
 * @CreateDate: 2024/12/18
 * @Version: v1.0.0
 */
@Component
public class KaptchaFilter extends OncePerRequestFilter {
    /**
     * 前端输入的验证码图形参数
     */
    private String codeParameter = "imageCode";

    /**
     * 自定义认证失败处理器
     */
    @Autowired
    private AuthenticationFailureHandler failureHandler;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 1.非post请求的表单提交不校验 图形验证码
        if (request.getMethod().equals("POST")) {
            try {
                // 2.校验图形验证码的合法性
                this.validateImageCode(request);
            } catch (KaptchaNotMatchException e) {
                failureHandler.onAuthenticationFailure(request, response, e);
                return;
            }
        }
        // 3.放行,进入下一个过滤器
        filterChain.doFilter(request, response);
    }

    /**
     * 判断图形验证码的合法性: 如果验证码匹配，则允许请求继续执行。如果不匹配，则抛出一个KaptchaNotMatchException异常
     *
     * @param request 请求对象
     */
    private void validateImageCode(HttpServletRequest request) {
        // 1.获取用户传入的图形验证码值
        String requestCode = request.getParameter(this.codeParameter);
        if (requestCode == null) {
            requestCode = "";
        }
        requestCode = requestCode.trim();

        // 2.获取服务器存储在session中的验证码值
        HttpSession session = request.getSession();
        CheckCode sessionCode = (CheckCode) session.getAttribute(Constants.KAPTCHA_SESSION_KEY);
        if (sessionCode != null) {
            // 清除验证码,不管成功与否,客户端应该在登录失败后 刷新验证码
            session.removeAttribute(Constants.KAPTCHA_SESSION_KEY);
        }

        // 检查用户输入的验证码是否为空。
        if (StringUtils.isBlank(requestCode)) {
            throw new KaptchaNotMatchException("验证码的值不能为空");
        }

        // 检查Session中是否存在验证码
        if (sessionCode == null) {
            throw new KaptchaNotMatchException("验证码不存在");
        }

        // 检查验证码是否已经过期。
        if (sessionCode.isExpired()) {
            throw new KaptchaNotMatchException("验证码过期");
        }

        // 最后比较用户输入的验证码与Session中的验证码是否一致（忽略大小写）。
        if (!requestCode.equalsIgnoreCase(sessionCode.getCode())) {
            throw new KaptchaNotMatchException("验证码输入错误");
        }
    }
}
